
/*
 * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package com.dc.gameserver.extComponents.Kit.util.random;

import java.security.SecureRandom;
import java.util.Random;

/**
 * 获取随机数工具
 * eg:Rnd.newInstance(RandomType.UNSECURE_VOLATILE).getInt(1,9)
 *    --this method is best ,please see detail
 *    Rnd.getInt(1,9)
 */
public final class Rnd {

	public static final class NonAtomicRandom extends Random{
		private static final long serialVersionUID = 1L;
		private volatile long _seed;
		
		public NonAtomicRandom(){
			this(++SEED_UNIQUIFIER + System.nanoTime());
		}
		
		public NonAtomicRandom(final long seed){
			setSeed(seed);
		}
		
		@Override
		public final int next(final int bits){
			return (int) ((_seed = (_seed * MULTIPLIER + ADDEND) & MASK) >>> (48 - bits));
		}
		
		@Override
		public final void setSeed(final long seed){
			_seed = (seed ^ MULTIPLIER) & MASK;
		}
	}
	
	/**
	 * 
	 * @author Forsaiken
	 *
	 */
	public static final class RandomContainer{
		private final Random _random;
		
		private RandomContainer(final Random random){
			_random = random;
		}
		
		public final Random directRandom(){
			return _random;
		}
		
		/**
		 * 获取 double值   0 to 1
		 * 
		 * @return A random double number from 0 to 1
		 * @see #nextDouble()
		 */
		public final double getDouble(){
			return _random.nextDouble();
		}
		
		/**
		 * 获取 integer  值 ；0-n
		 * 
		 * @param n
		 *            The superior limit (exclusive)
		 * @return A random integer number from 0 to n-1
		 */
		public final int getInt(final int n){
			return (int) (_random.nextDouble() * n);
		}
		
		/**
         * 获取区间随机值（min--max）integer
		 * Gets a random integer number from min(inclusive) to max(inclusive)
		 * 
		 * @param min
		 *            The minimum value
		 * @param max
		 *            The maximum value
		 * @return A random integer number from min to max
		 */
		public final int getInt(final int min, final int max){
			return min + (int) (_random.nextDouble() * (max - min + 1));
		}
		
		/**
		 * 获取区间随机值（min--max）long
		 * 
		 * @param min
		 *            The minimum value
		 * @param max
		 *            The maximum value
		 * @return A random long number from min to max
		 */
		public final long getlong(final long min, final long max){
			return min + (long) (_random.nextDouble() * (max - min + 1));
		}
		
		/**
		 * 获取随机 boolean state (true or false)
		 * 
		 * @return A random boolean state (true or false)
		 * @see java.util.Random#nextBoolean()
		 */
		public final boolean nextBoolean(){
			return _random.nextBoolean();
		}
		
		/**
		 * byte--【 Byte.MIN_VALUE(inclusive) to Byte.MAX_VALUE(inclusive)】随机值 填充array
		 * 
		 * @param array
		 *            The array to be filled with random byte numbers
		 * @see java.util.Random#nextBytes(byte[] bytes)
		 */
		public final void nextBytes(final byte[] array){
			_random.nextBytes(array);
		}
		
		/**
		 * 获取随机的 double 值 from 0 to 1
		 * 
		 * @return A random double number from 0 to 1
		 * @see java.util.Random#nextDouble()
		 */
		public final double nextDouble(){
			return _random.nextDouble();
		}
		
		/**
		 * 获取随机的 float 值  number from 0 to 1
		 * 
		 * @return A random integer number from 0 to 1
		 * @see java.util.Random#nextFloat()
		 */
		public final float nextFloat(){
			return _random.nextFloat();
		}
		
		/**
		 * 获取随机的 gaussian double 值  number from 0 to 1
		 * 
		 * @return A random gaussian double number from 0 to 1
		 * @see java.util.Random#nextGaussian()
		 */
		public final double nextGaussian(){
			return _random.nextGaussian();
		}
		
		/**
		 * Get a random integer number from Integer.MIN_VALUE(inclusive) to Integer.MAX_VALUE(inclusive)
		 * 
		 * @return A random integer number from Integer.MIN_VALUE to Integer.MAX_VALUE
		 * @see java.util.Random#nextInt()
		 */
		public final int nextInt(){
			return _random.nextInt();
		}
		
		/**
		 * Get a random long number from Long.MIN_VALUE(inclusive) to Long.MAX_VALUE(inclusive)
		 * 
		 * @return A random integer number from Long.MIN_VALUE to Long.MAX_VALUE
		 * @see java.util.Random#nextLong()
		 */
		public final long nextLong(){
			return _random.nextLong();
		}
	}
	
	/**
	 * 
	 * @author Forsaiken
	 *
	 */
	public static enum RandomType{
		/**
		 * 获取最佳随机值
		 * 
		 * @see java.security.SecureRandom
		 */
		SECURE,

		/**
		 * 获取平均随机值
		 * 
		 * @see java.util.Random
		 */
		UNSECURE_ATOMIC,

		/**
		 *  获取平均随机值
		 *  每个线程都有Random对象
		 *  提供并行的访问
		 *
		 * @see com.dc.gameserver.ExtComponents.Kit.util.random.Rnd.ThreadLocalRandom
		 */
		UNSECURE_THREAD_LOCAL,

		/**
		 * 获取平均随机值
		 * 速度更快 ，提供并行的访问
		 *
		 * @see com.dc.gameserver.ExtComponents.Kit.util.random.Rnd.NonAtomicRandom
		 */
		UNSECURE_VOLATILE
	}
	
	/**
	 * This class extends {@link java.util.Random} but do not compare and store atomically.<br>
	 * Instead it`s using thread local ensure reading and storing the whole 64bit seed chunk.<br>
	 * This implementation is the fastest, never generates the same seed for 2 threads.<br>
	 * Each thread has it`s own random instance.
	 * 
	 * @author Forsaiken
	 * @see java.util.Random
	 */
	public static final class ThreadLocalRandom extends Random{
		private static final class Seed{
			long _seed;
			
			Seed(final long seed){
				setSeed(seed);
			}
			
			final int next(final int bits){
				return (int) ((_seed = (_seed * MULTIPLIER + ADDEND) & MASK) >>> (48 - bits));
			}
			
			final void setSeed(final long seed){
				_seed = (seed ^ MULTIPLIER) & MASK;
			}
		}
		
		private static final long serialVersionUID = 1L;
		private final ThreadLocal<Seed> _seedLocal;
		
		public ThreadLocalRandom(){
			_seedLocal = new ThreadLocal<Seed>(){
				@Override
				public final Seed initialValue()
				{
					return new Seed(++SEED_UNIQUIFIER + System.nanoTime());
				}
			};
		}
		
		public ThreadLocalRandom(final long seed){
			_seedLocal = new ThreadLocal<Seed>(){
				@Override
				public final Seed initialValue(){
					return new Seed(seed);
				}
			};
		}
		
		@Override
		public final int next(final int bits){
			return _seedLocal.get().next(bits);
		}
		
		@Override
		public final void setSeed(final long seed){
			if (_seedLocal != null)
				_seedLocal.get().setSeed(seed);
		}
	}
	
	private final static long ADDEND = 0xBL;
	
	private final static long MASK = (1L << 48) - 1;
	
	private final static long MULTIPLIER = 0x5DEECE66DL;
	
	private static final RandomContainer rnd = newInstance(RandomType.UNSECURE_THREAD_LOCAL);
	
	private static volatile long SEED_UNIQUIFIER = 8682522807148012L;
	
	public static final Random directRandom(){
		return rnd.directRandom();
	}
	
	/**
	 * 获取 double  值 ；0-nnumber from 0 to 1
	 * 
	 * @return A random double number from 0 to 1
	 * @see #nextDouble()
	 */
	public static final double getDouble(){
		return rnd.nextDouble();
	}
	
	/**
	 * 获取 integer  值 ；0-n
	 * 
	 * @param n
	 *            The superior limit (exclusive)
	 * @return A random integer number from 0 to n-1
	 */
	public static final int getInt(final int n){
		return rnd.getInt(n);
	}
	
	/**
	 *  获取区间随机值（min--max）integer
	 * 
	 * @param min
	 *            The minimum value
	 * @param max
	 *            The maximum value
	 * @return A random integer number from min to max
	 */
	public static final int getInt(final int min, final int max){
		return rnd.getInt(min,max);
	}
	
	/**
	 * Gets a random long number from min(inclusive) to max(inclusive)
	 * 
	 * @param min
	 *            The minimum value
	 * @param max
	 *            The maximum value
	 * @return A random long number from min to max
	 */
	public static final long getlong(final long min, final long max){
		return rnd.getlong(min, max);
	}

    /**
     *
     * 随机数容器 根据RandomType，返回指定的容器---产生调用相应的随机数产生方式
     * @param type
     * @return
     */
	public static final RandomContainer newInstance(final RandomType type){
		switch (type){
			case UNSECURE_ATOMIC:
				return new RandomContainer(new Random());
				
			case UNSECURE_VOLATILE:
				return new RandomContainer(new NonAtomicRandom());
				
			case UNSECURE_THREAD_LOCAL:
				return new RandomContainer(new ThreadLocalRandom());
				
			case SECURE:
				return new RandomContainer(new SecureRandom());
		}
		
		throw new IllegalArgumentException();
	}
	
	/**
	 * Get a random boolean state (true or false)
	 * 
	 * @return A random boolean state (true or false)
	 * @see java.util.Random#nextBoolean()
	 */
	public static final boolean nextBoolean(){
		return rnd.nextBoolean();
	}
	
	/**
	 * Fill the given array with random byte numbers from Byte.MIN_VALUE(inclusive) to Byte.MAX_VALUE(inclusive)
	 * 
	 * @param array
	 *            The array to be filled with random byte numbers
	 * @see java.util.Random#nextBytes(byte[] bytes)
	 */
	public static final void nextBytes(final byte[] array){
		rnd.nextBytes(array);
	}
	
	/**
	 * Get a random double number from 0 to 1
	 * 
	 * @return A random double number from 0 to 1
	 * @see java.util.Random#nextDouble()
	 */
	public static final double nextDouble()
	{
		return rnd.nextDouble();
	}
	
	/**
	 * Get a random float number from 0 to 1
	 * 
	 * @return A random integer number from 0 to 1
	 * @see java.util.Random#nextFloat()
	 */
	public static final float nextFloat()
	{
		return rnd.nextFloat();
	}
	
	/**
	 * Get a random gaussian double number from 0 to 1
	 * 
	 * @return A random gaussian double number from 0 to 1
	 * @see java.util.Random#nextGaussian()
	 */
	public static final double nextGaussian(){
		return rnd.nextGaussian();
	}
	
	/**
	 * Get a random integer number from Integer.MIN_VALUE(inclusive) to Integer.MAX_VALUE(inclusive)
	 * 
	 * @return A random integer number from Integer.MIN_VALUE to Integer.MAX_VALUE
	 * @see java.util.Random#nextInt()
	 */
	public static final int nextInt()
	{
		return rnd.nextInt();
	}
	
	/**
	 * @param n 
	 * @return 
	 * @see #getInt(int)
	 */
	public static final int nextInt(final int n){
		return getInt(n);
	}
	
	/**
	 * Get a random long number from Long.MIN_VALUE(inclusive) to Long.MAX_VALUE(inclusive)
	 * 
	 * @return A random integer number from Long.MIN_VALUE to Long.MAX_VALUE
	 * @see java.util.Random#nextLong()
	 */
	public static final long nextLong(){
		return rnd.nextLong();
	}


    public static void main(String[]args){
//        System.out.println(Rnd.getInt(1,900000));
        System.out.println(Rnd.newInstance(RandomType.UNSECURE_VOLATILE).getDouble());
        long t1= System.nanoTime();
        System.out.println("times:"+(System.nanoTime()-t1));
    }
}
